#include "RingQueue.hpp"
#include "Task.hpp"
#include <unistd.h>
char ops[] = {'+', '-', '*', '/', '%', '.'};
template<class T>
class ThreadData
{
public:
    ThreadData()
    {}
    ThreadData(std::string name, RingQueue<T>* rq)
    :_name(name), _rq(rq)
    {}
public:
    std::string _name;
    RingQueue<T>* _rq;
};
void* Product(void* args)
{
    std::cout << "aaa" << std::endl;
    ThreadData<Task>* td = static_cast<ThreadData<Task>*>(args);
    while(true)
    {
        int x = rand() % 10;
        usleep(rand() % 123);
        int y = rand() % 10;
        usleep(rand() % 123);
        char op = ops[rand() % 6];
        Task t(x, y, op);
        std::cout << "Productor task" << t.PrintTask() << ',' << td->_name << std::endl;
        td->_rq->Push(t);
    }
    return nullptr;

}

void* Consume(void* args)
{
    ThreadData<Task>* td = static_cast<ThreadData<Task>*>(args);
    std::cout << "kkk" << std::endl;
    while(true)
    {
        Task t;
        td->_rq->Pop(&t);
        t();
        std::cout << "Customer task" << t.PrintResult() << ',' << td->_name << std::endl; 
    }

    return nullptr;
}
int main()
{
    srand((u_int64_t)time(nullptr) ^ getpid());
    // pthread_t p[3], c[2];
    pthread_t p, c;
    RingQueue<Task>* rq = new RingQueue<Task>;
    std::string name1 = "Thread-1";
    std::string name2 = "Thread-2";
    // std::string name3 = "Thread-3";
    // std::string name4 = "Thread-4";
    // std::string name5 = "Thread-5";

    ThreadData<Task>* td1 = new ThreadData<Task>(name1, rq);
    ThreadData<Task>* td2 = new ThreadData<Task>(name2, rq);

    pthread_create(&p, nullptr, Product, td1);
    pthread_create(&c, nullptr, Consume, td2);

    pthread_join(p, nullptr);
    pthread_join(c, nullptr);
    // ThreadData<Task>* td1 = new ThreadData<Task>(name1, rq);
    // ThreadData<Task>* td2 = new ThreadData<Task>(name2, rq);
    // ThreadData<Task>* td3 = new ThreadData<Task>(name3, rq);
    // ThreadData<Task>* td4 = new ThreadData<Task>(name4, rq);
    // ThreadData<Task>* td5 = new ThreadData<Task>(name5, rq);
    // pthread_create(&p[0], nullptr, Product, td1);
    // pthread_create(&p[1], nullptr, Product, td2);
    // pthread_create(&p[2], nullptr, Product, td3);
    // pthread_create(&c[0], nullptr, Consume, td4);
    // pthread_create(&c[1], nullptr, Consume, td5);
    
    // pthread_join(c[0], nullptr);
    // pthread_join(c[1], nullptr);
    // pthread_join(p[2], nullptr);
    // pthread_join(p[0], nullptr);
    // pthread_join(p[1], nullptr);

    return 0;
}